// src/utils/http.ts

// 定义请求配置类型
interface RequestConfig extends RequestInit {
    baseURL?: string;
    params?: Record<string, any>;
    timeout?: number;
}

// 定义拦截器类型
interface Interceptors {
    request?: (config: RequestConfig) => RequestConfig;
    response?: (response: Response) => Response | Promise<Response>;
    error?: (error: Error) => Promise<never>;
}

// 封装 fetch
class FetchClient {
    private baseURL: string;
    private interceptors: Interceptors = {};

    constructor(baseURL: string = '') {
        this.baseURL = baseURL;
    }

    // 设置拦截器
    public setInterceptors(interceptors: Interceptors): void {
        this.interceptors = interceptors;
    }

    // 发起请求
    public async request<T>(url: string, config: RequestConfig = {}): Promise<T> {
        // 合并 baseURL
        const fullURL = this.baseURL + url;

        // 处理 query 参数
        if (config.params) {
            const queryString = new URLSearchParams(config.params).toString();
            url += `?${queryString}`;
        }

        // 请求拦截器
        if (this.interceptors.request) {
            config = this.interceptors.request(config);
        }

        // 设置超时
        const timeout = config.timeout || 10000; // 默认 10 秒
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), timeout);

        try {
            // 发起请求
            let response = await fetch(fullURL, {
                ...config,
                signal: controller.signal,
            });

            // 清除超时
            clearTimeout(timeoutId);

            // 响应拦截器
            if (this.interceptors.response) {
                response = await this.interceptors.response(response);
            }

            // 自动处理错误状态码
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            // 返回 JSON 数据
            return response.json();
        } catch (error) {
            // 错误拦截器
            if (this.interceptors.error) {
                return this.interceptors.error(error as Error);
            }
            throw error;
        }
    }

    // 封装 GET 请求
    public get<T>(url: string, config?: RequestConfig): Promise<T> {
        return this.request(url, { ...config, method: 'GET' });
    }

    // 封装 POST 请求
    public post<T>(url: string, data?: any, config?: RequestConfig): Promise<T> {
        return this.request(url, {
            ...config,
            method: 'POST',
            body: JSON.stringify(data),
            headers: {
                'Content-Type': 'application/json',
                ...config?.headers,
            },
        });
    }

    // 封装 PUT 请求
    public put<T>(url: string, data?: any, config?: RequestConfig): Promise<T> {
        return this.request(url, {
            ...config,
            method: 'PUT',
            body: JSON.stringify(data),
            headers: {
                'Content-Type': 'application/json',
                ...config?.headers,
            },
        });
    }

    // 封装 DELETE 请求
    public delete<T>(url: string, config?: RequestConfig): Promise<T> {
        return this.request(url, { ...config, method: 'DELETE' });
    }
}

// 创建实例
const http = new FetchClient('http://localhost:5000');

// 设置拦截器
http.setInterceptors({
    request: (config) => {
        console.log('Request Interceptor:', config);
        // 在请求发送之前做一些处理，例如注入 Token
        const token = localStorage.getItem('token');
        if (token) {
            config.headers = {
                ...config.headers,
                Authorization: `Bearer ${token}`,
            };
        }
        return config;
    },
    response: (response) => {
        console.log('Response Interceptor:', response);
        // 对响应数据做一些处理
        return response;
    },
    error: (error) => {
        console.error('Error Interceptor:', error);
        // 对错误做一些处理
        return Promise.reject(error);
    },
});

export default http;